package org.wu.framework.lazy.orm.database.lambda.stream.condition.part;

import org.wu.framework.core.NormalUsedString;
import org.wu.framework.core.utils.ObjectUtils;
import org.wu.framework.lazy.orm.core.factory.LazyTableIdFactory;
import org.wu.framework.lazy.orm.core.factory.LazyTableStructureConverterFactory;
import org.wu.framework.lazy.orm.core.persistence.analyze.EasyAnnotationConverter;
import org.wu.framework.lazy.orm.core.persistence.conf.*;
import org.wu.framework.lazy.orm.core.persistence.util.LazySQLUtil;
import org.wu.framework.lazy.orm.core.stereotype.LazyFieldStrategy;
import org.wu.framework.lazy.orm.core.stereotype.LazyTableFieldId;
import org.wu.framework.lazy.orm.database.lambda.domain.Persistence;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * LazyTableUpsertConverterFactory 对象转化成 upsert 工厂
 *
 * @author wujiawei
 */
public class LazyTableSqlPartConverterFactory {


    /**
     * 将对象转换成 对应的 upsert 语句
     *
     * @param bean          对象
     * @return insertWithSet 语句
     */
    public static SqlPart upsert(Object bean ) {
        return insert(bean,Persistence.ExecutionEnum.UPSERT);
    }


    /**
     * 将对象转换成 对应的 insertWithSet 语句
     *
     * @param bean          对象
     * @return insertWithSet 语句
     */
    public static SqlPart insert(Object bean ) {
        return insert(bean,Persistence.ExecutionEnum.INSERT);
    }

    /**
     * 将对象转换成 对应的 insertWithSet 语句
     *
     * @param bean          对象
     * @param executionEnum 执行类型
     * @return insertWithSet 语句
     */
    public static SqlPart insert(Object bean, Persistence.ExecutionEnum executionEnum ) {
        SqlPart sqlPart = new SqlPart();

        sqlPart.setExecutionEnum(executionEnum);
        LazyTableStructure lazyTableStructure = LazyTableStructureConverterFactory.dataStructure(bean);

        LazyTableEndpoint lazyTableEndpoint = lazyTableStructure.schema();
        List<List<LazyTableFieldEndpoint>> payload = lazyTableStructure.payload();

        String fullTableName = lazyTableEndpoint.getFullTableName();

        // 设置主表
        sqlPart.setPrimaryTable(fullTableName);

        // 设置数据
        List<HashMap<String, Object>> mapList = payload.stream()
                .map(lazyTableFieldEndpoints -> lazyTableFieldEndpoints
                        .stream()
                        .filter(fieldLazyTableFieldEndpoint -> !LazyFieldStrategy.NEVER.equals(fieldLazyTableFieldEndpoint.getUpsertStrategy()))
                        .filter(convertedField -> !LazyDatabaseJsonMessage.ignoredFields.contains(convertedField.getName()))
                        .collect(HashMap<String, Object>::new, (map, lazyTableFieldEndpoint) -> {
                            Object fieldValue = lazyTableFieldEndpoint.getFieldValue();

                            // 输入的主键添加策略
                            if (ObjectUtils.isEmpty(fieldValue) && LazyTableFieldId.IdType.INPUT_ID.equals(lazyTableFieldEndpoint.getIdType())) {
                                Class<?> clazz = lazyTableFieldEndpoint.getClazz();
                                fieldValue = LazyTableIdFactory.createId(clazz);
                            }

                            // 条件判断
                            LazyFieldStrategy upsertStrategy = lazyTableFieldEndpoint.getUpsertStrategy();
                            if (LazyFieldStrategy.NOT_EMPTY.equals(upsertStrategy) && NormalUsedString.EMPTY.equals(fieldValue)) {
                                throw new RuntimeException(String.format("字段【%s】不能为空字符串", lazyTableFieldEndpoint.getField()));
                            }
                            if (LazyFieldStrategy.NOT_NULL.equals(upsertStrategy) && null == fieldValue) {
                                throw new RuntimeException(String.format("字段【%s】不能为NULL", fieldValue));
                            }
                            fieldValue = LazySQLUtil.valueToSqlValue(fieldValue);
                            if (null != fieldValue) {
                                fieldValue = EasyAnnotationConverter.annotationConvertConversion(lazyTableFieldEndpoint.getField(),
                                        fieldValue, lazyTableEndpoint.getIEnumList());
                                fieldValue = (Object) fieldValue.toString();
                            } else {
                                //                                fieldVal = JavaBasicTypeDefaultValue.DEFAULT_VALUE_HASHMAP.get(field.getMysqlType());
                                fieldValue = null;
                            }

                            map.put(lazyTableFieldEndpoint.getColumnName(), fieldValue);
                        }, HashMap::putAll)
                )
                .collect(Collectors.toList());
        sqlPart.setInsert(mapList);
        // 添加ON DUPLICATE KEY UPDATE
        List<LazyTableFieldEndpoint> convertedFieldList = lazyTableEndpoint.getLazyTableFieldEndpointList();

        Map<String, Object> insertDuplicateKey = convertedFieldList.stream()
                .filter(lazyTableFieldEndpoint -> !LazyFieldStrategy.NEVER_JOIN_DUPLICATE_KEY.equals(lazyTableFieldEndpoint.getUpsertStrategy()))
                .collect(Collectors.toMap(LazyTableFieldEndpoint::getColumnName, lazyTableFieldEndpoint -> {
                    // 拓展 获取自定义触发器中的数据进行数据填充
                    return NormalUsedString.VALUES
                            + NormalUsedString.SPACE + NormalUsedString.LEFT_BRACKET + lazyTableFieldEndpoint.getColumnName() +
                            NormalUsedString.RIGHT_BRACKET;
                }));
        sqlPart.setInsertDuplicateKey(insertDuplicateKey);


        return sqlPart;
    }


    /**
     * 将对象转换成 对应的 insertWithSet 语句
     *
     * @param schema 数据库
     * @param table  表
     * @param bean   对象、map
     * @return insertWithSet 语句
     */
    public static SqlPart upsertWeak(String schema, String table, Object bean) {
        String tableName = ObjectUtils.isEmpty(schema) ? table : schema + "." + table;
        return insertWeak(bean, tableName, Persistence.ExecutionEnum.UPSERT);
    }

    /**
     * 将对象转换成 对应的 insertWithSet 语句
     *
     * @param schema 数据库
     * @param table  表
     * @param bean   对象、map
     * @return insertWithSet 语句
     */
    public static SqlPart insertWeak(String schema, String table, Object bean) {
        String tableName = ObjectUtils.isEmpty(schema) ? table : schema + "." + table;
        return insertWeak(bean, tableName, Persistence.ExecutionEnum.INSERT);
    }


    /**
     * 将对象转换成 对应的 insertWithSet 语句
     *
     * @param bean          弱对象
     * @param tableName     表名称
     * @param executionEnum 执行类型
     * @return 执行sql
     * <p>
     * SourceFactory.defaultAnalyzeLazyTableFromMap(tableName,bean)
     * </p>
     */
    public static SqlPart insertWeak(Object bean, String tableName,Persistence.ExecutionEnum executionEnum) {
        SqlPart sqlPart = new SqlPart();
        sqlPart.setExecutionEnum(executionEnum);
        sqlPart.setPrimaryTable(tableName);

        // 解析出 字段
        LazyTableWeakStructure lazyTableWeakStructure = LazyTableStructureConverterFactory.weakDataStructure(bean);

        // 解析出 数据 TODO 中文集特殊字符
        List<HashMap<String/*column*/, Object/*value*/>> insert =
                lazyTableWeakStructure
                        .payload()
                        .stream()
                        .map(stringObjectMap -> {
                            Map<String, Object> objectMap = stringObjectMap
                                    .entrySet()
                                    .stream()
                                    .collect(
                                            Collectors
                                                    .toMap(
                                                            stringObjectEntry -> NormalUsedString.BACKTICK + stringObjectEntry.getKey() + NormalUsedString.BACKTICK,
                                                            Map.Entry::getValue,
                                                            (existing, _) -> existing, // 处理重复键
                                                            LinkedHashMap::new
                                                    )
                                    );

                            return new HashMap<>(objectMap);
                        })
                        .toList();


        sqlPart.setInsert(insert);

        // 添加ON DUPLICATE KEY UPDATE
        Map<String, Object> insertDuplicateKey = lazyTableWeakStructure
                .schema()
                .stream()
                .collect(Collectors.toMap(Function.identity(), columnName -> {
                    // 拓展 获取自定义触发器中的数据进行数据填充
                    return NormalUsedString.VALUES
                            + NormalUsedString.SPACE + NormalUsedString.LEFT_BRACKET + columnName +
                            NormalUsedString.RIGHT_BRACKET;
                }));
        sqlPart.setInsertDuplicateKey(insertDuplicateKey);
        return sqlPart;
    }
}
